﻿/* System.Compute: a Computation Framework for .NET/Mono
 * Copyright (C) 2011 Ralf "raboni" Boeckhorst
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General
 * Public License along with this library; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA
 */

using System.Runtime.InteropServices;

namespace System.Compute.OpenCL
{
    [StructLayout(LayoutKind.Sequential)]
    public struct SizeT
    {
        IntPtr Value;

        public int Size
        {
            get
            {
                return Marshal.SizeOf(this);
            }
        }

        //
        // ============================================================
        //

        public static implicit operator SizeT(int obj)
        {
            SizeT tmp = new SizeT();
            tmp.Value = (IntPtr)obj;
            return tmp;
        }

        public static implicit operator SizeT(long obj)
        {
            SizeT tmp = new SizeT();
            tmp.Value = (IntPtr)obj;
            return tmp;
        }

        public static implicit operator SizeT(IntPtr obj)
        {
            SizeT tmp = new SizeT();
            tmp.Value = obj;
            return tmp;
        }

        public static implicit operator int(SizeT obj)
        {
            return (int)obj.Value;
        }

        public static implicit operator long(SizeT obj)
        {
            return (long)obj.Value;
        }

        public static implicit operator IntPtr(SizeT obj)
        {
            return obj.Value;
        }

        //
        // ============================================================
        //

        public override int GetHashCode()
        {
            return (int)((long)Value >> 32) ^ (int)Value;
        }

        public override bool Equals(object obj)
        {
            if (obj.GetType() != typeof(SizeT))
                return false;
            SizeT p_obj = (SizeT)obj;
            if (p_obj.Value != Value)
                return false;
            return true;
        }
        
        public static bool operator ==(SizeT a, SizeT b)
        {
            return a.Value == b.Value;
        }

        public static bool operator !=(SizeT a, SizeT b)
        {
            return a.Value != b.Value;
        }

        public static bool operator <(SizeT a, SizeT b)
        {
            return (long)a < (long)b;
        }

        public static bool operator <=(SizeT a, SizeT b)
        {
            return (long)a <= (long)b;
        }

        public static bool operator >(SizeT a, SizeT b)
        {
            return (long)a > (long)b;
        }

        public static bool operator >=(SizeT a, SizeT b)
        {
            return (long)a >= (long)b;
        }

        public static SizeT operator +(SizeT a, SizeT b)
        {
            SizeT tmp = new SizeT();
            if (tmp.Size == 4)
                tmp.Value = (IntPtr)((int)a.Value + (int)b.Value);
            else
                tmp.Value = (IntPtr)((long)a.Value + (long)b.Value);
            return tmp;
        }

        public static SizeT operator +(SizeT a)
        {
            SizeT tmp = new SizeT();
            if (tmp.Size == 4)
                tmp.Value = (IntPtr)(+(int)a.Value);
            else
                tmp.Value = (IntPtr)(+(long)a.Value);
            return tmp;
        }

        public static SizeT operator ++(SizeT a)
        {
            SizeT tmp = new SizeT();
            if (tmp.Size == 4)
                tmp.Value = (IntPtr)((int)a.Value + 1);
            else
                tmp.Value = (IntPtr)((long)a.Value + 1);
            return tmp;
        }

        public static SizeT operator -(SizeT a, SizeT b)
        {
            SizeT tmp = new SizeT();
            if (tmp.Size == 4)
                tmp.Value = (IntPtr)((int)a.Value - (int)b.Value);
            else
                tmp.Value = (IntPtr)((long)a.Value - (long)b.Value);
            return tmp;
        }

        public static SizeT operator -(SizeT a)
        {
            SizeT tmp = new SizeT();
            if (tmp.Size == 4)
                tmp.Value = (IntPtr)(-(int)a.Value);
            else
                tmp.Value = (IntPtr)(-(long)a.Value);
            return tmp;
        }

        public static SizeT operator --(SizeT a)
        {
            SizeT tmp = new SizeT();
            if (tmp.Size == 4)
                tmp.Value = (IntPtr)((int)a.Value - 1);
            else
                tmp.Value = (IntPtr)((long)a.Value - 1);
            return tmp;
        }

        public static SizeT operator *(SizeT a, SizeT b)
        {
            SizeT tmp = new SizeT();
            if (tmp.Size == 4)
                tmp.Value = (IntPtr)((int)a.Value * (int)b.Value);
            else
                tmp.Value = (IntPtr)((long)a.Value * (long)b.Value);
            return tmp;
        }

        public static SizeT operator /(SizeT a, SizeT b)
        {
            SizeT tmp = new SizeT();
            if (tmp.Size == 4)
                tmp.Value = (IntPtr)((int)a.Value / (int)b.Value);
            else
                tmp.Value = (IntPtr)((long)a.Value / (long)b.Value);
            return tmp;
        }

        //
        // ============================================================
        //

        public override string ToString()
        {
            return Value.ToString();
        }
    }
}
